Skip to main content

How-To Guides

Build a production bundle

npm run build

The static site is emitted to dist/. Preview the built output with:

npm run preview

Type-check the project

There is no separate test suite; type-checking is the gate:

npm run lint

This runs tsc --noEmit against tsconfig.json.

Build and run with Docker

The Dockerfile is a two-stage build: Node builds the Vite bundle, then nginx serves dist/ on port 80 with an SPA fallback (try_files $uri $uri/ /index.html, see nginx.conf).

docker build -t i-saw-portal .
docker run --rm -p 8080:80 i-saw-portal

Then open http://localhost:8080.

To stamp the image with the commit it was built from, pass the build argument:

docker build --build-arg BUILD_SHA=$(git rev-parse --short HEAD) -t i-saw-portal .

Deploy to ICICLE infrastructure

Deployment is automated. .github/workflows/deploy.yaml runs on every push to main (and can be triggered manually from the Actions tab) and calls the shared reusable workflow icicle-ai/cicd-templates/.github/workflows/deploy-service.yaml@main.

The workflow needs three repository secrets:

  • TAPIS_TOKEN
  • REGISTRY_USERNAME
  • REGISTRY_PASSWORD

Service identity and runtime come from icicle-service.yaml:

FieldValue
service-namei-saw-frontend
service-version0.1.0
project-nameicicle-project
pod-nameisawfrontendprod
runtime-typenode-frontend
runtime-version24.18

Bump service-version in that file when you cut a new release.

Configure environment variables

Copy the example file if you need local overrides:

cp .env.example .env

.env.example documents GEMINI_API_KEY and APP_URL, which the AI Studio hosting environment injects at runtime. Neither variable is read by the current src/ code — the portal builds and runs without a .env file. Never commit real secrets.

Disable hot module reload

Agent-driven editing environments can flicker under HMR. Set DISABLE_HMR=true before starting the dev server to turn off both HMR and file watching (see vite.config.ts):

DISABLE_HMR=true npm run dev

Work on the right files (team ownership)

This repository enforces per-tab file ownership to avoid merge conflicts. Before editing, check CLAUDE.md for the current rules:

TabOwnerPrimary file
1 — Infrastructure / VisionAll team memberssrc/components/TabVision.tsx
2 — Smart Honeypot & AnalyticsManassrc/components/TabSandbox.tsx
3 — Onboarding HubJacobsrc/components/TabOnboarding.tsx

src/App.tsx and src/components/CanvasBackground.tsx are global; change them only with team agreement.

Troubleshooting

  • Port 3000 already in use — edit the dev script in package.json, or run npx vite --port=3001.
  • A route 404s behind your own web server — the app is a client-side SPA. Rewrite unknown paths to index.html, as nginx.conf does.
  • npm run lint fails after adding a package — install the matching @types/* package.
  • New dependency rejected in review — the project deliberately limits itself to React, Tailwind, lucide-react, and motion. Add heavier libraries only with team sign-off.